home *** CD-ROM | disk | FTP | other *** search
/ Sprite 1984 - 1993 / Sprite 1984 - 1993.iso / src / cmds / lpr / RCS / printcap.c,v < prev    next >
Encoding:
Text File  |  1988-11-23  |  8.5 KB  |  457 lines

  1. head     1.1;
  2. branch   ;
  3. access   ;
  4. symbols  ;
  5. locks    ; strict;
  6. comment  @ * @;
  7.  
  8.  
  9. 1.1
  10. date     88.11.23.10.31.53;  author rab;  state Exp;
  11. branches ;
  12. next     ;
  13.  
  14.  
  15. desc
  16. @@
  17.  
  18.  
  19.  
  20. 1.1
  21. log
  22. @Initial revision
  23. @
  24. text
  25. @/*
  26.  * Copyright (c) 1983 Regents of the University of California.
  27.  * All rights reserved.
  28.  *
  29.  * Redistribution and use in source and binary forms are permitted
  30.  * provided that this notice is preserved and that due credit is given
  31.  * to the University of California at Berkeley. The name of the University
  32.  * may not be used to endorse or promote products derived from this
  33.  * software without specific prior written permission. This software
  34.  * is provided ``as is'' without express or implied warranty.
  35.  */
  36.  
  37. #ifndef lint
  38. static char sccsid[] = "@@(#)printcap.c    5.2 (Berkeley) 5/5/88";
  39. #endif /* not lint */
  40.  
  41. #define MAXHOP    32    /* max number of tc= indirections */
  42.  
  43. #ifdef sprite
  44. #include "lp.h"
  45. #else
  46. #define    BUFSIZ    1024
  47. #include <ctype.h>
  48. #include <stdio.h>
  49. #endif
  50.  
  51. /*
  52.  * termcap - routines for dealing with the terminal capability data base
  53.  *
  54.  * BUG:        Should use a "last" pointer in tbuf, so that searching
  55.  *        for capabilities alphabetically would not be a n**2/2
  56.  *        process when large numbers of capabilities are given.
  57.  * Note:    If we add a last pointer now we will screw up the
  58.  *        tc capability. We really should compile termcap.
  59.  *
  60.  * Essentially all the work here is scanning and decoding escapes
  61.  * in string capabilities.  We don't use stdio because the editor
  62.  * doesn't, and because living w/o it is not hard.
  63.  */
  64.  
  65. #define PRINTCAP
  66.  
  67. #ifdef PRINTCAP
  68. #define tgetent    pgetent
  69. #define tskip    pskip
  70. #define tgetstr    pgetstr
  71. #define tdecode pdecode
  72. #define tgetnum    pgetnum
  73. #define    tgetflag pgetflag
  74. #define tdecode pdecode
  75. #define tnchktc    pnchktc
  76. #define    tnamatch pnamatch
  77. #undef E_TERMCAP
  78. #define E_TERMCAP "/etc/printcap"
  79. #define V6
  80. #endif
  81.  
  82. static    FILE *pfp = NULL;    /* printcap data base file pointer */
  83. static    char *tbuf;
  84. static    int hopcount;        /* detect infinite loops in termcap, init 0 */
  85. char    *tskip();
  86. char    *tgetstr();
  87. char    *tdecode();
  88. char    *getenv();
  89.  
  90. /*
  91.  * Similar to tgetent except it returns the next enrty instead of
  92.  * doing a lookup.
  93.  */
  94. getprent(bp)
  95.     register char *bp;
  96. {
  97.     register int c, skip = 0;
  98.  
  99.     if (pfp == NULL && (pfp = fopen(E_TERMCAP, "r")) == NULL)
  100.         return(-1);
  101.     tbuf = bp;
  102.     for (;;) {
  103.         switch (c = getc(pfp)) {
  104.         case EOF:
  105.             fclose(pfp);
  106.             pfp = NULL;
  107.             return(0);
  108.         case '\n':
  109.             if (bp == tbuf) {
  110.                 skip = 0;
  111.                 continue;
  112.             }
  113.             if (bp[-1] == '\\') {
  114.                 bp--;
  115.                 continue;
  116.             }
  117.             *bp = '\0';
  118.             return(1);
  119.         case '#':
  120.             if (bp == tbuf)
  121.                 skip++;
  122.         default:
  123.             if (skip)
  124.                 continue;
  125.             if (bp >= tbuf+BUFSIZ) {
  126.                 write(2, "Termcap entry too long\n", 23);
  127.                 *bp = '\0';
  128.                 return(1);
  129.             }
  130.             *bp++ = c;
  131.         }
  132.     }
  133. }
  134.  
  135. endprent()
  136. {
  137.     if (pfp != NULL)
  138.         fclose(pfp);
  139. }
  140.  
  141. /*
  142.  * Get an entry for terminal name in buffer bp,
  143.  * from the termcap file.  Parse is very rudimentary;
  144.  * we just notice escaped newlines.
  145.  */
  146. tgetent(bp, name)
  147.     char *bp, *name;
  148. {
  149.     register char *cp;
  150.     register int c;
  151.     register int i = 0, cnt = 0;
  152.     char ibuf[BUFSIZ];
  153.     char *cp2;
  154.     int tf;
  155.  
  156.     tbuf = bp;
  157.     tf = 0;
  158. #ifndef V6
  159.     cp = getenv("TERMCAP");
  160.     /*
  161.      * TERMCAP can have one of two things in it. It can be the
  162.      * name of a file to use instead of /etc/termcap. In this
  163.      * case it better start with a "/". Or it can be an entry to
  164.      * use so we don't have to read the file. In this case it
  165.      * has to already have the newlines crunched out.
  166.      */
  167.     if (cp && *cp) {
  168.         if (*cp!='/') {
  169.             cp2 = getenv("TERM");
  170.             if (cp2==(char *) 0 || strcmp(name,cp2)==0) {
  171.                 strcpy(bp,cp);
  172.                 return(tnchktc());
  173.             } else {
  174.                 tf = open(E_TERMCAP, 0);
  175.             }
  176.         } else
  177.             tf = open(cp, 0);
  178.     }
  179.     if (tf==0)
  180.         tf = open(E_TERMCAP, 0);
  181. #else
  182.     tf = open(E_TERMCAP, 0);
  183. #endif
  184.     if (tf < 0)
  185.         return (-1);
  186.     for (;;) {
  187.         cp = bp;
  188.         for (;;) {
  189.             if (i == cnt) {
  190.                 cnt = read(tf, ibuf, BUFSIZ);
  191.                 if (cnt <= 0) {
  192.                     close(tf);
  193.                     return (0);
  194.                 }
  195.                 i = 0;
  196.             }
  197.             c = ibuf[i++];
  198.             if (c == '\n') {
  199.                 if (cp > bp && cp[-1] == '\\'){
  200.                     cp--;
  201.                     continue;
  202.                 }
  203.                 break;
  204.             }
  205.             if (cp >= bp+BUFSIZ) {
  206.                 write(2,"Termcap entry too long\n", 23);
  207.                 break;
  208.             } else
  209.                 *cp++ = c;
  210.         }
  211.         *cp = 0;
  212.  
  213.         /*
  214.          * The real work for the match.
  215.          */
  216.         if (tnamatch(name)) {
  217.             close(tf);
  218. #ifdef sprite
  219.             return 1;
  220. #else
  221.             return(tnchktc());
  222. #endif
  223.         }
  224.     }
  225. }
  226.  
  227. #ifndef sprite
  228. /*
  229.  * tnchktc: check the last entry, see if it's tc=xxx. If so,
  230.  * recursively find xxx and append that entry (minus the names)
  231.  * to take the place of the tc=xxx entry. This allows termcap
  232.  * entries to say "like an HP2621 but doesn't turn on the labels".
  233.  * Note that this works because of the left to right scan.
  234.  */
  235. tnchktc()
  236. {
  237.     register char *p, *q;
  238.     char tcname[16];    /* name of similar terminal */
  239.     char tcbuf[BUFSIZ];
  240.     char *holdtbuf = tbuf;
  241.     int l;
  242.  
  243.     p = tbuf + strlen(tbuf) - 2;    /* before the last colon */
  244.     while (*--p != ':')
  245.         if (p<tbuf) {
  246.             write(2, "Bad termcap entry\n", 18);
  247.             return (0);
  248.         }
  249.     p++;
  250.     /* p now points to beginning of last field */
  251.     if (p[0] != 't' || p[1] != 'c')
  252.         return(1);
  253.     strcpy(tcname,p+3);
  254.     q = tcname;
  255.     while (q && *q != ':')
  256.         q++;
  257.     *q = 0;
  258.     if (++hopcount > MAXHOP) {
  259.         write(2, "Infinite tc= loop\n", 18);
  260.         return (0);
  261.     }
  262.     if (tgetent(tcbuf, tcname) != 1)
  263.         return(0);
  264.     for (q=tcbuf; *q != ':'; q++)
  265.         ;
  266.     l = p - holdtbuf + strlen(q);
  267.     if (l > BUFSIZ) {
  268.         write(2, "Termcap entry too long\n", 23);
  269.         q[BUFSIZ - (p-tbuf)] = 0;
  270.     }
  271.     strcpy(p, q+1);
  272.     tbuf = holdtbuf;
  273.     return(1);
  274. }
  275. #endif
  276. /*
  277.  * Tnamatch deals with name matching.  The first field of the termcap
  278.  * entry is a sequence of names separated by |'s, so we compare
  279.  * against each such name.  The normal : terminator after the last
  280.  * name (before the first field) stops us.
  281.  */
  282. tnamatch(np)
  283.     char *np;
  284. {
  285.     register char *Np, *Bp;
  286.  
  287.     Bp = tbuf;
  288.     if (*Bp == '#')
  289.         return(0);
  290.     for (;;) {
  291.         for (Np = np; *Np && *Bp == *Np; Bp++, Np++)
  292.             continue;
  293.         if (*Np == 0 && (*Bp == '|' || *Bp == ':' || *Bp == 0))
  294.             return (1);
  295.         while (*Bp && *Bp != ':' && *Bp != '|')
  296.             Bp++;
  297.         if (*Bp == 0 || *Bp == ':')
  298.             return (0);
  299.         Bp++;
  300.     }
  301. }
  302.  
  303. /*
  304.  * Skip to the next field.  Notice that this is very dumb, not
  305.  * knowing about \: escapes or any such.  If necessary, :'s can be put
  306.  * into the termcap file in octal.
  307.  */
  308. static char *
  309. tskip(bp)
  310.     register char *bp;
  311. {
  312.  
  313.     while (*bp && *bp != ':')
  314.         bp++;
  315.     if (*bp == ':')
  316.         bp++;
  317.     return (bp);
  318. }
  319.  
  320. /*
  321.  * Return the (numeric) option id.
  322.  * Numeric options look like
  323.  *    li#80
  324.  * i.e. the option string is separated from the numeric value by
  325.  * a # character.  If the option is not found we return -1.
  326.  * Note that we handle octal numbers beginning with 0.
  327.  */
  328. tgetnum(id)
  329.     char *id;
  330. {
  331.     register int i, base;
  332.     register char *bp = tbuf;
  333.  
  334.     for (;;) {
  335.         bp = tskip(bp);
  336.         if (*bp == 0)
  337.             return (-1);
  338.         if (*bp++ != id[0] || *bp == 0 || *bp++ != id[1])
  339.             continue;
  340.         if (*bp == '@@')
  341.             return(-1);
  342.         if (*bp != '#')
  343.             continue;
  344.         bp++;
  345.         base = 10;
  346.         if (*bp == '0')
  347.             base = 8;
  348.         i = 0;
  349.         while (isdigit(*bp))
  350.             i *= base, i += *bp++ - '0';
  351.         return (i);
  352.     }
  353. }
  354.  
  355. /*
  356.  * Handle a flag option.
  357.  * Flag options are given "naked", i.e. followed by a : or the end
  358.  * of the buffer.  Return 1 if we find the option, or 0 if it is
  359.  * not given.
  360.  */
  361. tgetflag(id)
  362.     char *id;
  363. {
  364.     register char *bp = tbuf;
  365.  
  366.     for (;;) {
  367.         bp = tskip(bp);
  368.         if (!*bp)
  369.             return (0);
  370.         if (*bp++ == id[0] && *bp != 0 && *bp++ == id[1]) {
  371.             if (!*bp || *bp == ':')
  372.                 return (1);
  373.             else if (*bp == '@@')
  374.                 return(0);
  375.         }
  376.     }
  377. }
  378.  
  379. /*
  380.  * Get a string valued option.
  381.  * These are given as
  382.  *    cl=^Z
  383.  * Much decoding is done on the strings, and the strings are
  384.  * placed in area, which is a ref parameter which is updated.
  385.  * No checking on area overflow.
  386.  */
  387. char *
  388. tgetstr(id, area)
  389.     char *id, **area;
  390. {
  391.     register char *bp = tbuf;
  392.  
  393.     for (;;) {
  394.         bp = tskip(bp);
  395.         if (!*bp)
  396.             return (0);
  397.         if (*bp++ != id[0] || *bp == 0 || *bp++ != id[1])
  398.             continue;
  399.         if (*bp == '@@')
  400.             return(0);
  401.         if (*bp != '=')
  402.             continue;
  403.         bp++;
  404.         return (tdecode(bp, area));
  405.     }
  406. }
  407.  
  408. /*
  409.  * Tdecode does the grung work to decode the
  410.  * string capability escapes.
  411.  */
  412. static char *
  413. tdecode(str, area)
  414.     register char *str;
  415.     char **area;
  416. {
  417.     register char *cp;
  418.     register int c;
  419.     register char *dp;
  420.     int i;
  421.  
  422.     cp = *area;
  423.     while ((c = *str++) && c != ':') {
  424.         switch (c) {
  425.  
  426.         case '^':
  427.             c = *str++ & 037;
  428.             break;
  429.  
  430.         case '\\':
  431.             dp = "E\033^^\\\\::n\nr\rt\tb\bf\f";
  432.             c = *str++;
  433. nextc:
  434.             if (*dp++ == c) {
  435.                 c = *dp++;
  436.                 break;
  437.             }
  438.             dp++;
  439.             if (*dp)
  440.                 goto nextc;
  441.             if (isdigit(c)) {
  442.                 c -= '0', i = 2;
  443.                 do
  444.                     c <<= 3, c |= *str++ - '0';
  445.                 while (--i && isdigit(*str));
  446.             }
  447.             break;
  448.         }
  449.         *cp++ = c;
  450.     }
  451.     *cp++ = 0;
  452.     str = *area;
  453.     *area = cp;
  454.     return (str);
  455. }
  456. @
  457.